在這一天的學習中,我們將繼續探討 Swift 中的 Delegate 和 Protocol,並且會設計一個具體的多協議應用範例來進一步理解這些概念的實際運用。這次,我們將會使用一個動物分類的範例,來展示如何通過自定義的 delegate 和 protocol 實現不同類型的動物行為。
我們的目標是:
首先,定義我們的 AnimalSounds 協議和基礎的動物類別。
// 定義 AnimalSounds protocol
protocol AnimalSounds {
func makeSound()
}
我們可以開始定義兩個遵從 AnimalSounds 協議的類別,分別是狗和貓。
// 定義 Dog 類別,遵從 AnimalSounds protocol
class Dog: AnimalSounds {
var name: String
init(name: String) { self.name = name }
func makeSound() {
print("\(name) 🐕 says Woof! 汪汪汪")
}
}
// 定義 Cat 類別,遵從 AnimalSounds protocol
class Cat: AnimalSounds {
var name: String
init(name: String) { self.name = name }
func makeSound() {
print("\(name) 🐱 says Meow! 喵喵喵")
}
}
// 生成 Dog 和 Cat 的實例並呼叫方法
let dog = Dog(name: "Buddy")
dog.makeSound() // Buddy 🐕 says Woof! 汪汪汪
let cat = Cat(name: "Whiskers")
cat.makeSound() // Whiskers 🐱 says Meow! 喵喵喵
這是一個基礎的動物叫聲範例,我們使用了 AnimalSounds 協議來定義動物的叫聲行為。Dog 和 Cat 分別實現了該協議的 makeSound() 方法。
在上述範例中,我們直接呼叫了狗和貓的叫聲方法。接下來,讓我們看看如何通過 Delegate 機制來控制動物的叫聲。
// 定義 AnimalManager 類別,這個類別持有 AnimalSounds 協議的實例
class AnimalManager {
var animalDelegate: AnimalSounds?
func makeSound() {
animalDelegate?.makeSound() // 使用 Optional Chaining 避免 nil 的情況
}
}
// 創建 AnimalManager 實例
let animalManager = AnimalManager()
// 指定狗為代理對象
animalManager.animalDelegate = Dog(name: "Buddy")
animalManager.makeSound() // Buddy 🐕 says Woof! 汪汪汪
// 切換代理對象為貓
animalManager.animalDelegate = Cat(name: "Whiskers")
animalManager.makeSound() // Whiskers 🐱 says Meow! 喵喵喵
這裡,我們通過 AnimalManager 類別來管理動物叫聲的代理。只要設定代理為不同的動物,就能讓不同動物發聲。
接下來,我們設計更多的協議來擴展動物的行為,例如飛行能力和游泳能力。
// 定義飛行能力協議
protocol Flyable {
func fly()
}
// 定義游泳能力協議
protocol Swimmable {
func swim()
}
// 定義動物基礎類別
class Animal {
var name: String
init(name: String) { self.name = name }
func makeSound() {
print("Generic animal sound.")
}
}
// 定義鳥類別,遵從 Flyable 和 AnimalSounds 協議
class Bird: Animal, AnimalSounds, Flyable {
func fly() {
print("\(name) is flying!")
}
override func makeSound() {
print("\(name) chirps.")
}
}
// 定義魚類別,遵從 Swimmable 和 AnimalSounds 協議
class Fish: Animal, AnimalSounds, Swimmable {
func swim() {
print("\(name) is swimming!")
}
override func makeSound() {
print("\(name) bubbles.")
}
}
使用範例使用範例
// 生成鳥的實例並呼叫方法
let bird = Bird(name: "Robin")
bird.makeSound() // Robin chirps.
bird.fly() // Robin is flying!
// 生成魚的實例並呼叫方法
let fish = Fish(name: "Nemo")
fish.makeSound() // Nemo bubbles.
fish.swim() // Nemo is swimming!
在這個例子中,Bird 繼承了 Animal 並且遵從了 Flyable 和 AnimalSounds 協議,而 Fish 則遵從 Swimmable 和 AnimalSounds。這樣,我們可以設計出更多符合實際生活中不同能力的動物。
如果有一種既能游泳又能飛的魚呢?我們可以通過繼承來擴展其行為。
// 定義飛魚類別,繼承 Fish 並遵從 Flyable 協議
class FlyingFish: Fish, Flyable {
override func makeSound() {
print("\(name) makes a splashy sound.")
}
func fly() {
print("\(name) is flying above water!")
}
}
// 使用飛魚範例
let flyingFish = FlyingFish(name: "Skyfish")
flyingFish.makeSound() // Skyfish makes a splashy sound.
flyingFish.swim() // Skyfish is swimming!
flyingFish.fly() // Skyfish is flying above water!
今天我們進一步探索了 delegate 和 protocol 的應用,我們設計一個動物分類範例來展示了 Swift 中協議的強大靈活性。透過設計一個名為 AnimalSounds 的協議,我們能夠讓不同的動物類別如 Dog 和 Cat 各自實現其專屬的 makeSound() 方法,從而達到讓每種動物發出獨特聲音的效果。
接著,我們引入了 delegate 代理模式,並透過 AnimalManager 類別模擬了多樣動物管理的情境。這展示了如何使用代理機制來動態地切換動物的代理對象,使管理員能夠根據不同的動物類型呼叫相應的 makeSound() 方法。這樣的設計在實際應用中十分常見,例如管理不同模塊的任務分派或響應,進一步加強了程式的擴展性和靈活性。
除了單一協議的應用,我們還進一步探討了多協議應用的情況。藉由設計 Flyable 和 Swimmable 協議,並讓不同的動物類別如 Bird 和 Fish 各自遵從相應的協議,我們能夠實現動物不同行為的多態性表現。這不僅展示了 Swift 中類別多重繼承的功能(透過協議),也強調了如何讓同一個物件具有多種能力,例如「飛魚」既能游泳又能飛行的複合行為。
最後,我們還探討了協議和類別中同名方法的區別,以及如何避免在繼承層級中不必要的協議重覆。這有助於保持程式碼結構的簡潔和清晰,避免不必要的冗餘,並確保程式的可讀性。
透過這些範例,我們可以明白 Swift 的 delegate 和 protocol 機制不僅在協作和分工上提供了極大的靈活性,也讓我們能夠更有條理地設計應用程式的架構,無論是針對簡單的功能實現,還是針對複雜的多協議行為,都能輕鬆應對。